﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Workflow;
using System.Workflow.ComponentModel.Compiler;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm.SdkTypeProxy;
using System.Web.Services.Protocols;

namespace CrmContrib.Workflow.Activities.Opportunities
{
    [CrmWorkflowActivity( "Get opportunity contact by relationship", "CrmContrib \\ Opportunities" )]
    public class GetOpportunityContactActivity : Activity
    {
        [CrmInput( "Opportunity" )]
        [CrmReferenceTarget( "opportunity" )]
        [ValidationOption( ValidationOption.Required )]
        public Lookup Opportunity
        {
            get { return (Lookup)base.GetValue( OpportunityProperty ); }
            set { base.SetValue( OpportunityProperty, value ); }
        }

        public static readonly DependencyProperty OpportunityProperty = DependencyProperty.Register( "Opportunity", typeof( Lookup ), typeof( GetOpportunityContactActivity ) );

        [CrmInput( "Customer Relationship" )]
        [CrmReferenceTarget( "relationshiprole" )]
        [ValidationOption( ValidationOption.Required )]
        public Lookup CustomerRelationship
        {
            get { return (Lookup)base.GetValue( CustomerRelationshipProperty ); }
            set { base.SetValue( CustomerRelationshipProperty, value ); }
        }

        public static readonly DependencyProperty CustomerRelationshipProperty = DependencyProperty.Register( "CustomerRelationship", typeof( Lookup ), typeof( GetOpportunityContactActivity ) );

        private IEnumerable<Guid> LoadOpportunityRelationshipsWithRole( ICrmService crmService, Guid opportunityId )
        {
            //Get the opportunity relationship for the opportunity with the given customer role
            var query = new QueryExpression { EntityName = EntityName.customeropportunityrole.ToString(), ColumnSet = new ColumnSet() };
            query.ColumnSet.AddColumn( "customerid" );
            query.Criteria.AddCondition( "opportunityid", ConditionOperator.Equal, opportunityId );
            query.Criteria.AddCondition( "opportunityroleid", ConditionOperator.Equal, CustomerRelationship.Value );

            //get the customer account/contact id
            var response = (RetrieveMultipleResponse)crmService.Execute( new RetrieveMultipleRequest { ReturnDynamicEntities = true, Query = query } );
            foreach ( DynamicEntity item in response.BusinessEntityCollection.BusinessEntities )
            {
                yield return ( (CrmReference)item["customerid"] ).Value;
            }
        }

        private Guid LoadContact( ICrmService crmService, Guid customerId )
        {
            var projection = new ColumnSet();
            projection.Attributes.Add( "contactid" );

            var target = new TargetRetrieveContact { EntityId = customerId };
            try
            {
                var response = (RetrieveResponse)crmService.Execute( new RetrieveRequest { ColumnSet = projection, Target = target, ReturnDynamicEntities = true } );
                DynamicEntity contact = (DynamicEntity)response.BusinessEntity;
                if ( contact.Properties.Contains( "contactid" ) )
                    return ( (Key)contact["contactid"] ).Value;
            }
            catch ( SoapException )
            {
                HasAContact = new CrmBoolean( false );
            }
            return Guid.Empty;
        }

        protected override ActivityExecutionStatus Execute( ActivityExecutionContext executionContext )
        {
            var contextService = executionContext.GetService<IContextService>();
            var workflowContext = contextService.Context;
            var crmService = workflowContext.CreateCrmService();

            var customerId = LoadOpportunityRelationshipsWithRole( crmService, Opportunity.Value ).FirstOrDefault();

            HasAContact = new CrmBoolean( false );

            var contact = LoadContact( crmService, customerId );
            var isContactEntity = contact == Guid.Empty ? false : true;
            if ( isContactEntity )
            {
                Contact = new Lookup( "contact", contact );
                HasAContact = new CrmBoolean( true );
            }

            return base.Execute( executionContext );
        }

        [CrmOutput( "Contact" )]
        [CrmReferenceTarget( "contact" )]
        public Lookup Contact
        {
            get { return (Lookup)base.GetValue( ContactProperty ); }
            set { base.SetValue( ContactProperty, value ); }
        }

        public static readonly DependencyProperty ContactProperty = DependencyProperty.Register( "Contact", typeof( Lookup ), typeof( GetOpportunityContactActivity ) );

        [CrmOutput( "Has a contact" )]
        public CrmBoolean HasAContact
        {
            get { return (CrmBoolean)base.GetValue( HasAContactProperty ); }
            set { base.SetValue( HasAContactProperty, value ); }
        }

        public static readonly DependencyProperty HasAContactProperty = DependencyProperty.Register( "HasAContact", typeof( CrmBoolean ), typeof( GetOpportunityContactActivity ) );
    }
}
